#pragma once

#include<vector>
#include<queue>
class ObjectBattlerBase;
class ObjectBattler;
class ObjectActor;
class ObjectEnemy;
struct UsableItem;
struct Item;
struct Skill;
struct Battle;

struct AnimationRequestData;

struct RequestRecord {
	enum RequestType {
		None = -1,
		Skill, SkillMobilize,
		AnimationToTarget, 
		Damage
	};

	ObjectBattler* object;
	RequestType rType;
	vector<int> data;
	vector<AnimationRequestData*> aniReqData;
	RequestRecord(ObjectBattler* obj, RequestType rt, int dt);
	RequestRecord(ObjectBattler* obj, RequestType rt, vector<int> dt);
	RequestRecord(ObjectBattler* obj, RequestType rt, vector<int> dt, 
		vector<AnimationRequestData*> aqdt);
};
struct OperListener {
	ObjectBattler* object;
	RequestRecord record;
	bool finished;
	OperListener(ObjectBattler* obj, RequestRecord rec);
};

class Damage {
public:
	static double criticalRate;
	static double defendRate;
	enum DamageType {
		HPDamage, MPDamage, HPRecover, MPRecover, HPAbsorb, MPAbsorb
	};
	enum HitType {
		None = -1,
		Hit, Miss, Crit
	};
	Damage();
	Damage(ObjectBattlerBase* battler, UsableItem* item, ObjectBattlerBase* target, double rate = 1.0);
	Damage(ObjectBattler* battler, UsableItem* item, ObjectBattler* target, double rate = 1.0);

	Damage makeReverseDamage();
	bool isActiveDamage();
	bool isActiveReverseDamage();

	int getDamageValue(DamageType type);
	HitType getHitResult();
	UsableItem* getItem();
	ObjectBattler* getObject();
	ObjectBattler* getTarget();

private:
	void processDamage(double rate=1.0);

	bool activeDamage;
	bool activeReverseDamage;
	int damageValue[6];
	HitType hitResult;
	ObjectBattler* object;
	ObjectBattler* target;
	UsableItem* item;
};

static class BattleManager {
public:
	static enum BattleResult {
		None, Win, Lose, Tied
	};

	static void setupBattle(int id, int level = 1);
	static void endBattle();
	static void updateRecord();

	static bool passable(int x, int y);

	static void addScore(int val);
	static void addRecover(int val);

	static ObjectActor* getActor();
	static ObjectEnemy* getEnemy(int id);
	static int getEnemyCount();
	static Battle* getBattle();

	static int dist2D2(ObjectBattler* battler1, ObjectBattler* battler2);
	static int dist3D2(ObjectBattler* battler1, ObjectBattler* battler2);

	static int dist2D2(int x1, int y1, int x2, int y2);
	static int dist3D2(int x1, int y1, int z1, int x2, int y2, int z2);

	static int dist2D2(int dx, int dy);
	static int dist3D2(int dx, int dy, int dz);

	static vector<ObjectBattler*> getTargets(ObjectBattler* battler, Skill* skill);
	static vector<ObjectBattler*> getTargets(ObjectBattler* battler, Item* item);
	static vector<ObjectBattler*> getEnemiesFor(ObjectBattler* battler);
	static vector<ObjectBattler*> getFriendsFor(ObjectBattler* battler, bool deadOnly = false);

	static BattleResult battleResult();

	static void addOperListener(ObjectBattler* object, RequestRecord record);

	static int getLevel();
	static int getTime();
	static int getRecoverPoint();
	static int getHurtPoint();
	static int getBeHurtPoint();
	static double getDifficulty();
	static int getAdditionalScore();
	static int getJudge();
	static int getScore();
	static int getGold();

	static void update();
private:
	static bool win(); static bool lose(); static bool tied();

	static void initializeScore();

	static void createMap();
	static void createBattlers();
	static void createPlayer();
	static void createEnemies();

	static void updateBattlers();
	static void updateDirection();
	static void updateEnemiesAI();
	static void updateEnemyMoveAI(ObjectEnemy* enemy);
	static void updateEnemyBattleAI(ObjectEnemy* enemy);
	static void updateRequests();
	static void updateOperListeners();
	static void checkRequests();
	static void processRequests();
	static void processOperListeners();
	static void checkRequestsFor(ObjectBattler* battler);
	static void processRequestsFor(RequestRecord* record);
	static void processOperListener(OperListener* listener);

	static void dealDamage(ObjectBattler* battler, Skill* skill, ObjectBattler* target, double rate=1.0);

	static int calcJudgeLevel();

	static Battle* battle;
	static Bitmap* passableBitmap;

	static int level;
	static int score;
	static int time; static int recover;
	static int hurt; static int beHurt;
	static double difficulty; static int mhmp;

	static queue<RequestRecord> requestQueue;

	static ObjectActor* actor; 
	static vector<ObjectEnemy> enemies;

	static vector<OperListener> operListeners;
};